home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / dev / misc / CWeb31p9b_locale.lha / CWeb / Examples / matrix.wpp < prev    next >
Encoding:
Text File  |  1993-12-06  |  18.0 KB  |  483 lines

  1. %
  2. % CWEB $VER: matrix.wpp 1.1 (26.11.1993)
  3. %
  4. % BESCHREIBUNG: Dieses CWEB Programm soll als Beispiel für einige
  5. %               Erweiterungen dienen, die erst mit der neuen Version 3
  6. %               des CWEB-Systems verfügbar sind.  Es liest die Datei
  7. %               `Matrix.input', die in vier Zeilen jeweils vier Einträge
  8. %               der Form `(Realteil,Imaginärteil)' enthalten, und berechnet
  9. %               zu der so definierten komplexen Matrix die Inverse.  Ist
  10. %               die Eingabedatei nicht vorhanden, werden die entsprechenden
  11. %               Werte vom Benutzer angefordert.  Als Besonderheiten für
  12. %               CWEB-Interessierte möchte ich zwei Punkte anführen.  Zuerst
  13. %               und vor allem ist es ein deutsches Programm, sowohl die Ein-
  14. %               als auch die Ausgabe ist für diese Sprache gedacht.  Für die
  15. %               TeXnische Weiterverarbeitung wird also `gcwebmac.tex'
  16. %               benötigt, da dort die entsprechende Anpassung bezüglich
  17. %               der Umlaute und Anführungszeichen enthalten ist.
  18. %               Zweitens ist es ein C++ Programm und muß deshalb mit
  19. %               CWEB 3.0 verarbeitet werden; ältere Versionen ohne
  20. %               die Change-Datei von Hans-Hermann Bode werden ihre
  21. %               Schwierigkeiten haben.  Außerdem muß zur Übersetzung ein
  22. %               C++-Compiler benutzt werden.
  23. %
  24. % ERSTELLUNGSDATUM: 21.11.1993 (V1.0)
  25. %
  26. % AUTOR: Andreas Scherer
  27. %         Abt-Wolf-Straße 17
  28. %         96215 Lichtenfels
  29. %         Germany
  30. %
  31. % ÄNDERUNGEN: 26.11.1993: <stdlib.h> muß *nach* <complex.h> eingebunden
  32. %                         werden, sonst meckert SAS/C++ 6.50 (V1.1)
  33. %
  34. % URHEBERRECHT: (c) 1993 Andreas Scherer
  35. %
  36. % Die Anfertigung und Verteilung von unveränderten Kopien der
  37. % elektronischen Form dieses Dokumentes ist erlaubt, sofern der
  38. % Urheberrechtshinweis und dieser Berechtigungshinweis bei allen
  39. % Kopien erhalten bleibt.
  40. %
  41. % Die Anfertigung und Verteilung von veränderten Versionen dieses
  42. % Dokumentes ist erlaubt unter den Bedingungen für unveränderte Kopien,
  43. % sofern das gesamte hiervon abgeleitete Werk unter den Bedingungen eines
  44. % mit diesem vergleichbaren Berechtigungshinweises verteilt wird.
  45.  
  46. % Spezielle Fonts für Teile der Dokumentation.
  47. %
  48. \font\ams=msbm10
  49.  
  50. % Ein kleiner Trick zur Darstellung der Determinantenschreibweise, da
  51. % der senkrechte Strich in \.{CWEB} eine besondere Bedeutung besitzt.
  52. %
  53. \def\leftbar{\left|}
  54. \def\rightbar{\right|}
  55.  
  56. % Wir brauchen kein Inhaltsverzeichnis, da nur zwei Kapitel existieren.
  57. %
  58. \nocon
  59.  
  60. @* Matrizeninversion. Dieses Programm dient zur Invertierung einer
  61. vorgegebenen $4$-reihigen |Matrix|
  62. $$
  63.   A=\left(
  64.     \matrix{
  65.       a_{11}&\cdots&a_{14}\cr
  66.       \vdots&\ddots&\vdots\cr
  67.       a_{41}&\cdots&a_{44}\cr}
  68.   \right)
  69. $$
  70. mit Einträgen $a_{ij}$ aus dem Körper der komplexen Zahlen~{\ams C}.
  71. Ursprünglich wurde es auf einem {\mc PC} mit dem Borland~\CPLUSPLUS/
  72. Compiler entwickelt.  Ein Vorteil dieses Sprachdialektes ist die
  73. Bereitstellung des Datentypes \glqq komplexe Zahl\grqq.  Nach einem
  74. Zwischenstadium als {\mc ANSI-C}-Programm, das ich mit dem {\mc
  75. SAS/C}-6.3 aus der ursprünglichen Form entwickelte, erfolgt nun die
  76. Rückportierung nach \CPLUSPLUS/ mit der neuen Version~6.50 des {\mc
  77. SAS/C}-Systems.  Der Aufbau des Programmes selbst gliedert sich in
  78. folgende Teile:
  79.  
  80. @c
  81. @<Globale |#include|s  @>@/
  82. @<Versionsnummer       @>@/
  83. @<Funktionsprototypen  @>@/
  84. @<Funktionen           @>@/
  85. @<Die |main|-Funktion  @>
  86.  
  87. @ Den mathematischen Hintergrund für das angewandte Verfahren liefert
  88. das \glqq Taschenbuch der Mathematik\grqq\ von I.~N.~Bronstein und
  89. K.~A.~Semendjajew (B.~G.~Teubner Verlagsgesellschaft Stuttgart und
  90. Leipzig, 25.~Auf\-lage 1991, {\mc ISBN}~3--8154--2000--8).
  91. Auf Seite~154 wird die Berechnung einer inversen Matrix nach der Formel
  92. $$
  93.   Inverse = Matrix^{-1} = {1\over\det Matrix}\left(\matrix{
  94.     A_{11}&\cdots&A_{1n}\cr
  95.           &\cdots&      \cr
  96.     A_{n1}&\cdots&A_{nn}\cr}\right)^{T}
  97. $$
  98. hergeleitet.  Ausgangspunkt ist eine |Dimension|-reihigen |Matrix|, zu der
  99. in den folgenden Schritten die |Determinante| und die |Adjunkte| berechnet
  100. werden.  Bei der Berechnung der |Inverse|n anhand dieser Formel ist zu
  101. beachten, daß die Transposition der |Adjunkte|n einfach durch
  102. Vertauschung der Zeilen- und Spaltenindizes geschieht.
  103. @^Taschenbuch der Mathematik@>
  104. @^Bronstein, Ilja N.@>
  105. @^Semendjajew, K. A.@>
  106.  
  107. @<Berechne die |Inverse|@>=
  108.    for(i=0; i<Dimension; i++) {
  109.       for(j=0; j<Dimension; j++)
  110.          Inverse[i][j] = Adjunkte[j][i]/Determinante;
  111.       }
  112.  
  113. @ Der aufwendigste Teil dieser Formel steckt in der Berechnung der
  114. |Adjunkte|n zur $4$-reihigen komplexen |Matrix|.  (Die Dimension spielt
  115. mathematisch keine Rolle, programmtechnisch muß aber für andere
  116. |Dimension|en eine Anpassung vorgenommen werden.)  Diese setzt sich zusammen
  117. aus den algebraischen Komplementen~$A_{ij}$ der Elemente~$a_{ij}$ der
  118. |Matrix|, die sich nach der Formel
  119. $$
  120.   A_{ij} = (-1)^{i+j}\leftbar\matrix{
  121.     a_{11}   &\cdots&a_{1,j-1}  &a_{1,j+1}  &\cdots&a_{1n}   \cr
  122.     \ldots   &      &\ldots     &\ldots     &      &\ldots   \cr
  123.     a_{i-1,1}&\cdots&a_{i-1,j-1}&a_{i-1,j+1}&\cdots&a_{i-1,n}\cr
  124.     a_{i+1,1}&\cdots&a_{i+1,j-1}&a_{i+1,j+1}&\cdots&a_{i+1,n}\cr
  125.     \ldots   &      &\ldots     &\ldots     &      &\ldots   \cr
  126.     a_{n1}   &\cdots&a_{n,j-1}  &a_{n,j+1}  &\cdots&a_{nn}  \cr}
  127.   \rightbar
  128. $$
  129. berechnen (Bronstein, Seite~149, |n==Dimension|).  Für die
  130. Implementierung benötigen wir die $3$-reihige |Hilfsmatrix| und die
  131. Variable |Faktor|, die die Potenz von $-1$ repräsentiert.
  132. @^Taschenbuch der Mathematik@>
  133. @^Beschränkung der Allgemeinheit@>
  134.  
  135. @s complex int
  136.  
  137. @<Funktionen@>=
  138. void AdjunkteMatrix(complex **Matrix,complex **Adjunkte)
  139.    {
  140.    int i,j,corralloc = 1;
  141.    complex **Hilfsmatrix,Faktor;
  142.  
  143.    @<Allokiere die |Hilfsmatrix|@>@;
  144.  
  145.    if(corralloc) {
  146.       for(i=0; i<4; i++) {
  147.          @<Setze den Vorfaktor für die adjunkte Determinante@>@;
  148.  
  149.          for(j=0; j<4; j++) {
  150.             @<Streiche Zeile |i| und Spalte |j|               @>@;
  151.             @<Berechne die Determinante der |Hilfsmatrix|     @>@;
  152.             @<Multipliziere die Determinante mit dem Vorfaktor@>@;
  153.  
  154.             Faktor *= (complex)(-1.); /* |Faktor| wechselt spaltenweise */
  155.             }
  156.          }
  157.       }
  158.  
  159.    @<Gib den Speicher der |Hilfsmatrix| wieder frei@>@;
  160.    }
  161.  
  162. @ Der Vorfaktor in dieser allgemeinen Formel bestimmt sich aus der Potenz
  163. von~$-1$ nach der Summe aus Spaltennummer und Zeilennummer des gerade
  164. betrachteten |Matrix|elementes~$a_{ij}$.  Zu beachten ist dabei, daß in
  165. \CEE/ Vektoren und damit auch Matrizen nicht bei~$1$ sondern bei~$0$ beginnend
  166. indiziert werden.  Da es sich aber um ein zweidimensionales Objekt handelt,
  167. hebt sich die quadratische Potenz von~$-1$ wieder auf.
  168.  
  169. @<Setze den Vorfaktor für die adjunkte Determinante@>=
  170.    for(Faktor=(complex)1.,j=0; j<i; j++)
  171.       Faktor *= (complex)(-1.);
  172.  
  173. @ Die angegebene Determinantendarstellung besagt, daß man die
  174. Ausgangsmatrix um die Zeile~|i| und die Spalte~|j| des gerade betrachteten
  175. Elementes \glqq reduzieren\grqq\ muß, bevor man die Determinante
  176. berechnen darf.  Im Programm wird dazu aus der Ausgangsmatrix die
  177. entsprechend verkleinerte |Hilfsmatrix| gebildet.
  178.  
  179.  @<Streiche Zeile |i| und Spalte |j|@>=
  180.    MatrixReduktion(4,Matrix,Hilfsmatrix,i,j);
  181.  
  182. @ Die Reduktion der |Matrix| zur |Dimension-1|-reihigen |Hilfsmatrix|
  183. geschieht durch Streichen der Zeile~|i| und der Spalte~|j|.  Da dieser
  184. Vorgang für jedes der |Dimension|$^2$ Elemente der |Matrix|
  185. durchgeführt werden muß, wird dazu eine elementare Funktion
  186. definiert, die sogar mit einer anderen |Dimension| als~$4$ eingesetzt
  187. werden kann.  Die Zählvariablen |k| und~|l| bezeichnen die
  188. Zeilen beziehungsweise die Spalten der Ausgangs-|Matrix|, |m|~und~|n|
  189. die der |Hilfsmatrix|.
  190.  
  191. @<Funktionen@>=
  192. void MatrixReduktion(int Dimension,complex **Matrix,@|
  193. complex **Hilfsmatrix,int i,int j)
  194.    {
  195.    int k,l,m,n;
  196.  
  197.    for(k=0,m=0; k<Dimension; k++) {
  198.       if(k!=i) { /* Zeile wird ausgelassen für |k==i| */
  199.          for(l=0,n=0; l<Dimension; l++) {
  200.             if(l!=j) { /* Spalte wird ausgelassen für |l==j| */
  201.                Hilfsmatrix[m][n] = Matrix[k][l];
  202.                n++; /* Nächste Spalte der |Hilfsmatrix| */
  203.                }
  204.             }
  205.          m++; /* Nächste Zeile der |Hilfsmatrix| */
  206.          }
  207.       }
  208.    }
  209.  
  210. @ Als Zwischenschritt folgt nun die Berechnung der Determinante der
  211. |Hilfsmatrix|.  Diese wird bereits in das entsprechende Feld der
  212. |Adjunkte|n gestellt, das aber noch mit dem getrennt berechneten Faktor
  213. multipliziert werden muß.
  214.  
  215. @<Berechne die Determinante der |Hilfsmatrix|@>=
  216.    Adjunkte[i][j] = ComplexDet(Hilfsmatrix);
  217.  
  218. @ Im vorliegenden Programm zur Berechnung einer |Inverse|n der
  219. |Dimension|~$4$ haben wir es stets mit einer $3$-dimensionalen
  220. |Hilfsmatrix| zu tun.  Deren Determinante (beachte die Schreibweise) wird
  221. nach der Beispielformel~2 von Seite~149 aus Bronstein berechnet (Regel von
  222. Sarrus)
  223. $$
  224.   \leftbar\matrix{
  225.     a_{11}&a_{12}&a_{13}\cr
  226.     a_{21}&a_{22}&a_{23}\cr
  227.     a_{31}&a_{32}&a_{33}\cr}\rightbar=
  228.   (a_{11}a_{22}a_{33} + a_{12}a_{23}a_{31} + a_{13}a_{21}a_{32})-
  229.   (a_{13}a_{22}a_{31} + a_{11}a_{23}a_{32} + a_{12}a_{21}a_{33}).
  230. $$
  231. @^Taschenbuch der Mathematik@>
  232. @^Beschränkung der Allgemeinheit@>
  233.  
  234. @d ComplexDet(H) @/
  235.   (H[0][0]*H[1][1]*H[2][2]+H[0][1]*H[1][2]*H[2][0]+H[0][2]*H[1][0]*H[2][1])-@/
  236.   (H[0][2]*H[1][1]*H[2][0]+H[0][0]*H[1][2]*H[2][1]+H[0][1]*H[1][0]*H[2][2])
  237.  
  238. @ Der berechnete Zwischenwert muß noch mit dem vorher definierten 
  239. |Faktor| multipliziert werden, damit das endgültige algebraische
  240. Komplement~$A_{ij}$ entsteht.
  241.  
  242. @<Multipliziere die Determinante mit dem Vorfaktor@>=
  243.    Adjunkte[i][j] *= Faktor;
  244.  
  245. @ Nach der Aufstellung der |Adjunkte|n zur |Matrix| benötigen wir jetzt
  246. noch die |Determinante|.  Erfreulicherweise ist dazu nun kein großer
  247. Aufwand mehr nötig, da diese nach dem Laplaceschen Entwicklungssatz
  248. $$
  249.   Determinante=\sum_{i=1}^{n}a_{ij}A_{ij}=\sum_{j=1}^{n}a_{ij}A_{ij}
  250. $$
  251. aus den Elementen der |Matrix| und der zugehörigen |Adjunkte|n berechnet
  252. werden kann (Bronstein, Seite~150).  Dabei ist es egal, nach welcher Zeile
  253. oder Spalte die Entwicklung durchgeführt wird.  Wir verwenden die erste
  254. Spalte.
  255. @^Taschenbuch der Mathematik@>
  256.  
  257. @<Laplace-Entwicklung der |Determinante|n@>=
  258.    Determinante = (complex)0.;
  259.    for(i=0; i<Dimension; i++)
  260.       Determinante += Matrix[i][0]*Adjunkte[i][0];
  261.  
  262. @ Nach der Darlegung des mathematischen Formelwerkes und dessen Umsetzung
  263. in \CEE/-Routinen folgt nun das Hauptprogramm, das den Rahmen für die
  264. Anwendung der beschriebenen Funktionen bildet.  Zusätzlich verwendet es
  265. weitere Unterroutinen, die rein programmiertechnischer Natur sind und
  266. im folgenden unabhängig vom mathematischen Problem beschrieben werden.
  267.  
  268. @<Die |main|-Funktion@>=
  269. int main()
  270.    {
  271.    complex **Matrix,**Adjunkte,**Inverse;
  272.    complex Determinante;
  273.    int i,j,Dimension=4,corralloc=1;
  274.  
  275.    @<Allokiere die zu invertierende |Matrix|@>@;
  276.    @<Allokiere die |Adjunkte|               @>@;
  277.    @<Allokiere die |Inverse|                @>@;
  278.  
  279.    if(corralloc) {
  280.       MatrixInit(Dimension,Matrix);
  281.       MatrixDisplay(Dimension,Matrix);
  282.       AdjunkteMatrix(Matrix,Adjunkte);
  283.       @<Laplace-Entwicklung der |Determinante|n@>@;
  284.       @<Berechne die |Inverse|                 @>@;
  285.       MatrixDisplay(Dimension,Inverse);
  286.       }
  287.  
  288.    @<Gib den Speicher wieder frei@>@;
  289.    return(corralloc);
  290.    }
  291.  
  292. @ Für die formatierte Ein- und Ausgabe, die dynamische Speicherverwaltung
  293. sowie die mathematischen Funktionen benötigen wir die
  294. Standarddeklarationen, wie sie in den Include-Dateien zu finden sind.
  295.  
  296. @<Globale |#include|s@>=
  297. #include <math.h>
  298. #include <complex.h>
  299. #include <stdio.h>
  300. #include <stdlib.h>
  301. @<Zusätzliche Deklarationen für den Coprozessor@>
  302.  
  303. @ Bei der Benutzung des mathematischen Coprozessors sollten zusätzlich zu
  304. {\tt math.h} die speziellen Funktionsdeklarationen eingebunden werden.
  305. Dies gilt in diesem Fall speziell für den Commodore Amiga und den {\mc
  306. ANSI-C}-Compiler von {\mc SAS}~Institute, Cary (North Carolina).
  307.  
  308. @<Zusätzliche Deklarationen für den Coprozessor@>=
  309. #ifdef _M68881
  310. #include <m68881.h>
  311. #endif
  312. @^Systemabhängigkeiten@>
  313.  
  314. @ Die aktuelle Versionsnummer dieses Programmes wird nach dem \glqq Style
  315. Guide\grqq\ von Commodore in einer globalen Formatzeichenkette abgelegt und
  316. kann mit der Systemroutine {\tt version Matrix} abgefragt werden.
  317.  
  318. @<Versionsnummer@>=
  319. #ifdef QUATSCH
  320. static unsigned char *Version = "$VER: MATRIXINVERTIERUNG 2.0 (20.11.1993)";
  321. #endif
  322. @^Systemabhängigkeiten@>
  323.  
  324. @ Die meisten Routinen dieses Programmes sind unabhängig von der
  325. gewählten |Dimension| des Problems.  Alle aber stellen nur minimale
  326. Forderungen an die Gestalt der verwendeten Matrizen, da sie lediglich mit
  327. Zeigern auf entsprechende Felder versorgt werden müssen.  Damit
  328. läßt sich aber auch die Eingabe des Ausgangsproblems fast beliebig
  329. gestalten.  Bei dieser allgemeinen Implementierung kann dies auf zwei
  330. verschiedene Weisen geschehen.  Standardeingabe ist die Datei
  331. \glq{\tt Matrix.input}\grq, falls diese im aktuellen Verzeichnis vorhanden
  332. ist.  Falls nicht, wird der Benutzer zur elementweisen Eingabe der
  333. komplexen Elemente der |Matrix| aufgefordert.  Wird eine andere
  334. Verfahrensweise gewünscht, so muß lediglich diese Funktion zur Eingabe
  335. und die weiter unten beschriebene Funktion zur Ausgabe der Problemstellung
  336. geändert oder angepaßt werden.
  337.  
  338. @<Funktionen@>=
  339. void MatrixInit(int Dimension,complex **Matrix)
  340.    {
  341.    int i,j;
  342.    double Realteil,Imagteil;
  343.    FILE *fp;
  344.  
  345.    if(fp = fopen("Matrix.input","r")) {
  346.       for(i=0; i<Dimension; i++) {
  347.          for(j=0; j<Dimension; j++) {
  348.             fscanf(fp,"(%lf,%lf)",&Realteil,&Imagteil);
  349.             Matrix[i][j] = complex(Realteil,Imagteil);
  350.             }
  351.          }
  352.       fclose(fp);
  353.       }
  354.    else {
  355.       for(i=0; i<Dimension; i++) {
  356.          for(j=0; j<Dimension; j++) {
  357.             printf("Real A[%d][%d] = ",i+1,j+1);
  358.             scanf("%lf",&Realteil);
  359.             printf("Imag A[%d][%d] = ",i+1,j+1);
  360.             scanf("%lf",&Imagteil);
  361.             Matrix[i][j] = complex(Realteil,Imagteil);
  362.             }
  363.          fputc('\n',stdout);
  364.          }
  365.       }
  366.    }
  367. @^Beschränkung der Allgemeinheit@>
  368. @^Systemabhängigkeiten@>
  369.  
  370. @ Ebenso einfach wie die Eingabe ist auch die Ausgaberoutine gestaltet.
  371. Sie zeigt eine quadratische |Dimension|-reihige |Matrix| mit komplexen
  372. Einträgen zum einen am Bildschirm an und schreibt gleichzeitig das
  373. Ergebnis im gleichen Format in die Datei \glq{\tt Matrix.output}\grq, das
  374. beim Einlesen aus \glq{\tt Matrix.input}\grq\ erwartet wird.
  375.  
  376. @<Funktionen@>=
  377. void MatrixDisplay(int Dimension,complex **Matrix)
  378.    {
  379.    int i,j;
  380.    FILE *fp;
  381.  
  382.    fp = fopen("Matrix.output","w");
  383.    for(i=0; i<Dimension; i++) {
  384.       for(j=0; j<Dimension; j++) {
  385.          if(fp) fprintf(fp,"(%lf,%lf)",real(Matrix[i][j]),imag(Matrix[i][j]));
  386.          printf("(%lf,%lf) ",real(Matrix[i][j]),imag(Matrix[i][j]));
  387.          }
  388.       if(fp) fputc('\n',fp);
  389.       fputc('\n',stdout);
  390.       }
  391.    fputc('\n',stdout);
  392.    fclose(fp);
  393.    }
  394. @^Beschränkung der Allgemeinheit@>
  395. @^Systemabhängigkeiten@>
  396.  
  397. @ Was ein echtes \CEE/-Programm sein will, das verwendet so wenig wie
  398. möglich feste Größen bei der Definition von Speicherflächen.
  399. Zwar sind in diesem Fall alle Dimensionen bekannt und bei jedem Lauf immer
  400. gleich, aber trotzdem ist es eine nette Übung, den benötigten
  401. Speicherplatz \glqq dynamisch\grqq\ anzufordern und nach seiner Benutzung
  402. wieder ordnungsgemäß freizugeben.  Die |Matrix|, ihre |Adjunkte| und
  403. die zu berechnende |Inverse| werden lokal in |main| als Zeigervariablen
  404. definiert und erhalten auch lokal ihren Speicherplatz zugewiesen.
  405.  
  406. @<Allokiere die zu invertierende |Matrix|@>=
  407.    if(Matrix = (complex **)calloc(Dimension,sizeof(complex *))) {
  408.       for(i=0; i<Dimension; i++)
  409.          if(!(Matrix[i] = (complex *)calloc(Dimension,sizeof(complex))))
  410.             corralloc = 0;
  411.       }
  412.    else corralloc = 0;
  413.  
  414. @ @<Allokiere die |Adjunkte|@>=
  415.    if(Adjunkte = (complex **)calloc(Dimension,sizeof(complex *))) {
  416.       for(i=0; i<Dimension; i++)
  417.          if(!(Adjunkte[i] = (complex *)calloc(Dimension,sizeof(complex))))
  418.             corralloc = 0;
  419.       }
  420.    else corralloc = 0;
  421.  
  422. @ @<Allokiere die |Inverse|@>=
  423.    if(Inverse = (complex **)calloc(Dimension,sizeof(complex *))) {
  424.       for(i=0; i<Dimension; i++)
  425.          if(!(Inverse[i] = (complex *)calloc(Dimension,sizeof(complex))))
  426.             corralloc = 0;
  427.       }
  428.    else corralloc = 0;
  429.  
  430. @ Nach der erfolgreichen Durchführung aller Berechnungsschritte muß vor
  431. Beendigung des Programmes der angeforderte Speicher wieder freigegeben werden.
  432. Dies geschieht in umgekehrter Reihenfolge zur Allokierung.
  433.  
  434. @d FreeObject(A) if(A) free(A);
  435.  
  436. @<Gib den Speicher wieder frei@>=
  437.    for(i=Dimension-1; i>=0; i--) {
  438.       FreeObject(Inverse[i]);
  439.       FreeObject(Adjunkte[i]);
  440.       FreeObject(Matrix[i]);
  441.       }
  442.  
  443.    FreeObject(Inverse);
  444.    FreeObject(Adjunkte);
  445.    FreeObject(Matrix);
  446.  
  447. @ Noch radikaler als bei den genannten Matrizen erfolgt die Lokalisierung
  448. der |Hilfsmatrix|.  Sie wird erst innerhalb der Funktion |AdjunkteMatrix|
  449. definiert und mit Speicherplatz besorgt.
  450.  
  451. @<Allokiere die |Hilfsmatrix|@>=
  452.    if(Hilfsmatrix = (complex **)calloc(3,sizeof(complex *))) {
  453.       for(i=0; i<3; i++)
  454.          if(!(Hilfsmatrix[i] = (complex *)calloc(3,sizeof(complex))))
  455.             corralloc = 0;
  456.       }
  457.    else corralloc = 0;
  458. @^Beschränkung der Allgemeinheit@>
  459.  
  460. @ @<Gib den Speicher der |Hilfsmatrix| wieder frei@>=
  461.    for(i=0; i<3; i++) FreeObject(Hilfsmatrix[i]);
  462.    FreeObject(Hilfsmatrix);
  463. @^Beschränkung der Allgemeinheit@>
  464.  
  465. @ Als letztes Modul im Programmfluß angelegt, jedoch in der
  466. endgültigen \CEE/-Quelldatei sehr weit vorne, stehen hier die Prototypen
  467. aller verwendeten Funktionen.  Die Beschreibung der Parameterliste und die
  468. Angabe des Rückgabewertes ermöglicht es dem Compiler, eventuelle
  469. Programmierfehler festzustellen und zu melden.
  470.  
  471. @<Funktionsprototypen@>=
  472. void MatrixInit(int,complex **);                        @/
  473. void MatrixReduktion(int,complex **,complex **,int,int);@/
  474. void MatrixDisplay(int,complex **);                     @/
  475. void AdjunkteMatrix(complex **,complex **);             @/
  476. int main(void);
  477.  
  478. @* Index.  Zum Abschluß der Dokumentation folgen noch das
  479. Stichwortverzeichnis mit sämtlichen verwendeten Bezeichnern sowie eine
  480. Zusammenfassung aller Programmodule.  Zu beachten sind insbesondere die
  481. Einträge \glqq Beschränkung der Allgemeinheit\grqq\ und \glqq
  482. Systemabhängigkeiten\grqq.
  483.